import { ipcMain } from 'electron'
import crypto from 'crypto'
import path from 'path'
import fs from 'fs'
// 引入所需模块
const http = require('http');
const https = require('https');
const { URL } = require('url');
import { isEmpty } from 'lodash'
import { assetPath, ensureConfigInitialized, serviceUrl } from '../config/config.js'
import {
  selectPage,
  selectByStatus,
  updateStatus,
  remove as deleteVideo,
  findFirstByStatus,
} from '../dao/video.js'
import { selectByID as selectF2FModelByID, selectByIDCommonModel as selectF2FModelByCommonID } from '../dao/f2f-model.js'
import { selectByID as selectVoiceByID, selectByIDCommonVoice } from '../dao/voice.js'
import {
  insert as insertVideo,
  count,
  update,
  selectByID as selectVideoByID
} from '../dao/video.js'
import { makeAudio4Video, copyAudio4Video } from './voice.js'
import { makeVideo as makeVideoApi,getVideoStatus } from '../api/f2f.js'
import log from '../logger.js'
import { getVideoDuration } from '../util/ffmpeg.js'
import axios from 'axios'
import FormData from 'form-data'

const MODEL_NAME = 'video'

/**
 * 分页查询合成结果
 * @param {number} page
 * @param {number} pageSize
 * @returns
 */
function page({ page, pageSize, name = '' }) {
  // 查询的有waiting状态的视频
  const waitingVideos = selectByStatus('waiting').map((v) => v.id)
  const total = count(name)
  const list = selectPage({ page, pageSize, name }).map((video) => {
    video = {
      ...video,
      file_path: video.file_path ? assetPath.model + video.file_path : video.file_path
    }

    if(video.status === 'waiting'){
      video.progress = `${waitingVideos.indexOf(video.id) + 1} / ${waitingVideos.length}`
    }
    return video
  })

  return {
    total,
    list
  }
}

function findVideo(videoId, is_common) {
  const video = selectVideoByID(videoId)
  return {
    ...video,
    file_path: video.file_path ? assetPath.model + video.file_path : video.file_path
  }
}

function countVideo(name = '') {
  return count(name)
}

async function saveVideo({ id, model_id, name, text_content, voice_id, audio_path, caption_path }) {
  const video = selectVideoByID(id)
  if(audio_path){
    audio_path = await copyAudio4Video(audio_path)
  }

  if (video) {
    return update({ id, model_id, name, text_content, voice_id, audio_path, caption_path })
  }
  return insertVideo({ model_id, name, status: 'draft', text_content, voice_id, audio_path, caption_path })
}

/**
 * 合成视频
 * 更新视频状态为waiting
 * @param {number} videoId
 * @returns
 */
function makeVideo(videoId) {
  update({ id: videoId, status: 'waiting', is_common: "false" })
  return videoId
}

function makeVideoCommon(videoId) {
  update({ id: videoId, status: 'waiting', is_common: "true" })
  return videoId
}

export async function synthesisVideo(videoId, is_common) {
  try{
    update({
      id: videoId,
      file_path: null,
      status: 'pending',
      message: '正在提交任务',
    })

    // 查询Video
    const video = selectVideoByID(videoId)
    log.debug('~ selectVideoByID makeVideo ~ video:', video)

    let model;
    if (is_common === true || is_common === 'true') {
      model = await selectF2FModelByCommonID(video.model_id)
      log.debug('~ makeVideoCommon ~ model:', model)
    }else {
      // 根据modelId获取model信息
      model = selectF2FModelByID(video.model_id)
      log.debug('~ makeVideo ~ model:', model)
    }


    let audioPath
    if(video.audio_path){
      // 将audio_path复制到ttsProduct目录下
      audioPath = video.audio_path
    }else{
      let voice;
      // 根据model信息中的voiceId获取voice信息
      if (is_common === true || is_common === 'true') {
        console.log("makeVideoCommon model.voiceId" + model.voiceId)
        if (video.voiceId){
          voice = await selectByIDCommonVoice(video.voiceId)
        } else {
          voice = await selectByIDCommonVoice(model.voiceId)
        }
        log.debug('~ makeVideoCommon ~ voice:', voice)
      }else {
        voice = selectVoiceByID(video.voice_id || model.voice_id)
        log.debug('~ makeVideo ~ voice:', voice)
      }

      // 调用tts接口生成音频
      audioPath = await makeAudio4Video({
        voiceId: voice.id,
        text: video.text_content,
        is_common
      })
      log.debug('~ makeVideo ~ audioPath:', audioPath)
    }

    let video_path;
    if (is_common === true || is_common === 'true') {
      video_path = model.videoPath
    } else {
      video_path = model.video_path
    }

    // 调用视频生成接口生成视频
    let result, param
    // if (process.env.NODE_ENV === 'development') {
    //   // 写死调试
    //   ({ result, param } = await makeVideoByF2F('test.wav', 'test.mp4'))
    // } else {
      ({ result, param } = await makeVideoByF2F(audioPath, video_path))
    // }

    log.debug('~ makeVideo ~ result, param:', result, param)

    // 插入视频表
    if(10000 === result.code){ // 成功
      update({
        id: videoId,
        file_path: null,
        status: 'pending',
        message: result,
        audio_path: audioPath,
        param,
        code: param.code
      })
    }else{ // 失败
      update({
        id: videoId,
        file_path: null,
        status: 'failed',
        message: result.msg,
        audio_path: audioPath,
        param,
        code: param.code
      })
    }
  } catch (error) {
    log.error('~ synthesisVideo ~ error:', error.message)
    updateStatus(videoId, 'failed', error.message)
  }

  // 6. 返回视频id
  return videoId
}

export async function loopPending() {
  const video = findFirstByStatus('pending', 'false')
  if (!video) {
    synthesisNext('false')

    setTimeout(() => {
      loopPending()
    }, 2000)
    return
  }

  const statusRes = await getVideoStatus(video.code)
  console.log("statusRes" + statusRes)

  if ([9999, 10002, 10003].includes(statusRes.code)) {
    // updateStatus(video.id, 'failed', statusRes.msg)
    console.log(JSON.stringify(statusRes))
  } else if (statusRes.code === 10000) {
    if (statusRes.data.status === 1) {
      updateStatus(
        video.id,
        'pending',
        statusRes.data.msg,
        statusRes.data.progress,
      )
    } else if (statusRes.data.status === 2) { // 合成成功
      // ffmpeg 获取视频时长
      let duration
      // if(process.env.NODE_ENV === 'development'){
      //   duration = 88
      // }else{
        const resultPath = assetPath.model + statusRes.data.result
        duration = await getVideoDuration(resultPath)
      // }

      update({
        id: video.id,
        status: 'success',
        message: statusRes.data.msg,
        progress: statusRes.data.progress,
        file_path: statusRes.data.result,
        duration
      })

    } else if (statusRes.data.status === 3) {
      updateStatus(video.id, 'failed', statusRes.data.msg)
    }
  }

  setTimeout(() => {
    loopPending()
  }, 2000)
  return video
}

export async function loopPendingCommon() {
  const video = findFirstByStatus('pending', 'true')
  if (!video) {
    synthesisNext('true')

    setTimeout(() => {
      loopPendingCommon()
    }, 2000)
    return
  }

  const statusRes = await getVideoStatus(video.code)

  if ([9999, 10002, 10003].includes(statusRes.code)) {
    updateStatus(video.id, 'failed', statusRes.msg)
  } else if (statusRes.code === 10000) {
    if (statusRes.data.status === 1) {
      updateStatus(
        video.id,
        'pending',
        statusRes.data.msg,
        statusRes.data.progress,
      )
    }else if (statusRes.data.status === 2) { // 合成成功
      // ffmpeg 获取视频时长
      let duration
      // if(process.env.NODE_ENV === 'development'){
      //   duration = 88
      // }else{
        const resultPath = assetPath.model + statusRes.data.result
        duration = await getVideoDuration(resultPath)
      // }

      update({
        id: video.id,
        status: 'success',
        message: statusRes.data.msg,
        progress: statusRes.data.progress,
        file_path: statusRes.data.result,
        duration
      })

    } else if (statusRes.data.status === 3) {
      updateStatus(video.id, 'failed', statusRes.data.msg)
    }
  }

  setTimeout(() => {
    loopPendingCommon()
  }, 2000)
  return video
}

/**
 * 合成下一个视频
 */
function synthesisNext(is_common) {
  // 查询所有未完成的视频任务
  const video = findFirstByStatus('waiting', is_common)
  if (video) {
    synthesisVideo(video.id, is_common)
  }
}

function removeVideo(videoId) {
  // 查询视频
  const video = selectVideoByID(videoId)
  log.debug('~ removeVideo ~ videoId:', videoId)

  // 删除视频
  const videoPath = assetPath.model + video.file_path ||''
  if (!isEmpty(video.file_path) && fs.existsSync(videoPath)) {
    fs.unlinkSync(videoPath)
  }

  // 删除音频
  const audioPath = assetPath.model + video.audio_path ||''
  if (!isEmpty(video.audio_path) && fs.existsSync(audioPath)) {
    fs.unlinkSync(audioPath)
  }

  // 删除视频表
  return deleteVideo(videoId)
}

// 修改后的exportVideo函数
async function exportVideo(videoId, outputPath, is_caption) {
  const video = selectVideoByID(videoId);
  console.log('Output path:', outputPath);
  console.log('Asset model path:', assetPath.model);
  let fullPath;
  if (is_caption){
    console.log('Video file path:', video.video_with_caption_path);
    fullPath = video.video_with_caption_path;

  } else {
    console.log('Video file path:', video.file_path);
    // 构建完整文件路径或URL
    fullPath = assetPath.model + video.file_path;
  }

  console.log('Full path:', fullPath);

  // 检查是否为HTTP/HTTPS URL
  if (fullPath.startsWith('http://') || fullPath.startsWith('https://')) {
    try {
      // 使用HTTP/HTTPS下载
      await downloadFile(fullPath, outputPath);
      console.log('Video downloaded successfully to:', outputPath);
    } catch (err) {
      console.error('Error downloading video:', err);
      throw err;
    }
  } else {
    // 本地文件复制
    try {
      fs.copyFileSync(fullPath, outputPath);
      console.log('Video copied successfully to:', outputPath);
    } catch (err) {
      console.error('Error copying video:', err);
      throw err;
    }
  }
}

// 下载文件的辅助函数
function downloadFile(url, outputPath) {
  return new Promise((resolve, reject) => {
    // 确保输出目录存在
    const outputDir = path.dirname(outputPath);
    if (!fs.existsSync(outputDir)) {
      fs.mkdirSync(outputDir, { recursive: true });
    }

    // 创建写入流
    const fileStream = fs.createWriteStream(outputPath);

    // 解析URL以确定使用http还是https
    const parsedUrl = new URL(url);
    const requester = parsedUrl.protocol === 'https:' ? https : http;

    const request = requester.get(url, (response) => {
      // 处理重定向
      if (response.statusCode === 301 || response.statusCode === 302) {
        const redirectUrl = response.headers.location;
        fileStream.close();
        downloadFile(redirectUrl, outputPath)
          .then(resolve)
          .catch(reject);
        return;
      }

      // 检查响应状态码
      if (response.statusCode !== 200) {
        reject(new Error(`Failed to download file: ${response.statusCode} ${response.statusMessage}`));
        return;
      }

      // 写入文件
      response.pipe(fileStream);

      // 处理错误
      response.on('error', (err) => {
        fileStream.close();
        fs.unlinkSync(outputPath); // 删除不完整的文件
        reject(err);
      });

      // 完成下载
      fileStream.on('finish', () => {
        fileStream.close();
        resolve();
      });

      // 处理写入错误
      fileStream.on('error', (err) => {
        fileStream.close();
        fs.unlinkSync(outputPath); // 删除不完整的文件
        reject(err);
      });
    });

    // 处理请求错误
    request.on('error', (err) => {
      fileStream.close();
      fs.unlinkSync(outputPath); // 删除不完整的文件
      reject(err);
    });

    // 设置超时
    request.setTimeout(30000, () => {
      request.abort();
      fileStream.close();
      fs.unlinkSync(outputPath); // 删除不完整的文件
      reject(new Error('Request timeout'));
    });
  });
}

/**
 * 调用face2face生成视频
 * @param {string} audioPath
 * @param {string} videoPath
 * @returns
 */
async function makeVideoByF2F(audioPath, videoPath) {
  const uuid = crypto.randomUUID()
  const param = {
    audio_url: audioPath,
    video_url: videoPath,
    code: uuid,
    chaofen: 0,
    watermark_switch: 0,
    pn: 1
  }
  const result = await makeVideoApi(param)
  return { param, result }
}

function modify(video) {
  return update(video)
}

function transformSubtitlePath(subtitle_path) {
  // 将本地路径转换为网络路径
  const regex = /^([A-Za-z]):\\(.*)$/; // 匹配 "D:\" 这类格式
  const match = subtitle_path.match(regex);
  if (match) {
    // 如果匹配成功，转换为网络路径
    return `\\\\192.168.0.152\\${match[1].toLowerCase()}\\${match[2].replace(/\\/g, '\\\\')}`;
  }
  return subtitle_path;
}

async function captionVideo(videoId, file_path, caption_path, output_path) {
  // 参数验证
  if (!videoId) {
    throw new Error('videoId 参数不能为空');
  }

  if (!file_path || typeof file_path !== 'string') {
    throw new Error('file_path 参数必须是有效的字符串路径');
  }

  if (!caption_path || typeof caption_path !== 'string') {
    throw new Error('caption_path 参数必须是有效的字符串路径');
  }

  if (!output_path || typeof output_path !== 'string') {
    throw new Error('output_path 参数必须是有效的字符串路径');
  }

  // 检查字幕文件是否存在
  if (!fs.existsSync(caption_path)) {
    throw new Error(`字幕文件不存在: ${caption_path}`);
  }

  // 确保配置初始化完成
  await ensureConfigInitialized();

  const kpopBaseUrl = serviceUrl.kpopBaseUrl;

  try {
    // 第一步：上传字幕文件
    console.log('开始上传字幕文件...');
    const uploadedSubtitlePath = await uploadSubtitleFile(caption_path, kpopBaseUrl);

    // 第二步：烧录字幕到视频
    console.log('开始烧录字幕到视频...');
    const burnResult = await burnSubtitleToVideo(file_path, uploadedSubtitlePath, output_path, kpopBaseUrl);

    // 第三步：更新数据库
    console.log('字幕压视频成功，更新数据库...');
    const video = {
      id: videoId,
      video_with_caption_path: burnResult.output_path,
      with_caption: 1
    };
    await update(video, burnResult.output_path);

    return {
      success: true,
      output_path: burnResult.output_path,
      message: '字幕压视频成功'
    };

  } catch (error) {
    console.error('字幕压视频失败:', error);
    throw error;
  }
}

async function printedVideo(printedVideo) {
  console.log(JSON.stringify(printedVideo));

  // 确保配置初始化完成
  await ensureConfigInitialized();

  const kpopBaseUrl = serviceUrl.kpopBaseUrl;

  try {
    const response = await axios.put(`${kpopBaseUrl}:5000/api/tools/subtitle_videos_mappings`, printedVideo, {
      headers: {
        'accept': 'application/json'
      },
      timeout: 120000, // 2分钟超时
    });

    if (response.data && response.data.success) {
      console.log('发送加印花数据成功:', response.data.message);
      return true
    } else {
      throw new Error(`发送加印花数据失败: ${response.data?.message || '未知错误'}`);
    }

  } catch (error) {
    if (error.response) {
      throw new Error(
        `发送加印花数据失败，状态码: ${error.response.status}, ` +
        `错误: ${error.response.data?.message || error.response.statusText}`
      );
    } else {
      throw new Error(`发送加印花数据失败: ${error.message}`);
    }
  }
}

/**
 * 上传字幕文件到服务器
 * @param {string} caption_path - 字幕文件路径
 * @param {string} kpopBaseUrl - 服务器基础URL
 * @returns {Promise<string>} 上传后的字幕路径
 */
async function uploadSubtitleFile(caption_path, kpopBaseUrl) {
  const FormData = require('form-data');
  const path = require('path');

  const formData = new FormData();
  const subtitleFileName = path.basename(caption_path);

  formData.append('subtitle_file', fs.createReadStream(caption_path), {
    filename: subtitleFileName,
    contentType: 'text/plain'
  });

  try {
    const response = await axios.post(`${kpopBaseUrl}:5000/api/tools/subtitle`, formData, {
      headers: {
        ...formData.getHeaders(),
        'accept': 'application/json'
      },
      timeout: 120000, // 2分钟超时
      maxContentLength: Infinity,
      maxBodyLength: Infinity
    });

    if (response.data && response.data.success) {
      console.log('字幕文件上传成功:', response.data.subtitle_path);
      return transformSubtitlePath(response.data.subtitle_path);
    } else {
      throw new Error(`字幕文件上传失败: ${response.data?.message || '未知错误'}`);
    }

  } catch (error) {
    if (error.response) {
      throw new Error(
        `字幕文件上传失败，状态码: ${error.response.status}, ` +
        `错误: ${error.response.data?.message || error.response.statusText}`
      );
    } else {
      throw new Error(`字幕文件上传失败: ${error.message}`);
    }
  }
}

/**
 * 烧录字幕到视频
 * @param {string} video_path - 视频文件路径
 * @param {string} subtitle_path - 字幕文件路径
 * @param {string} output_path - 输出文件路径
 * @param {string} kpopBaseUrl - 服务器基础URL
 * @returns {Promise<Object>} 烧录结果
 */
async function burnSubtitleToVideo(video_path, subtitle_path, output_path, kpopBaseUrl) {
  const postData = {
    output_path: output_path,
    subtitle_path: subtitle_path,
    video_path: video_path
  };

  console.log('烧录字幕请求参数:', postData);

  try {
    const response = await axios.post(`${kpopBaseUrl}:5000/api/tools/burn_subtitle`, postData, {
      headers: {
        'Content-Type': 'application/json',
      },
      timeout: 120000, // 2分钟超时
    });

    if (response.data && response.data.success) {
      console.log("烧录字幕成功:", response.data);
      return response.data;
    } else {
      throw new Error(`烧录字幕失败: ${response.data?.message || '未知错误'}`);
    }

  } catch (error) {
    if (error.response) {
      throw new Error(
        `烧录字幕失败，状态码: ${error.response.status}, ` +
        `错误: ${error.response.data?.message || error.response.statusText}`
      );
    } else {
      throw new Error(`烧录字幕失败: ${error.message}`);
    }
  }
}

export function init() {
  ipcMain.handle(MODEL_NAME + '/page', (event, ...args) => {
    return page(...args)
  })
  ipcMain.handle(MODEL_NAME + '/make', (event, ...args) => {
    return makeVideo(...args)
  })
  ipcMain.handle(MODEL_NAME + '/make_common', (event, ...args) => {
    return makeVideoCommon(...args)
  })
  ipcMain.handle(MODEL_NAME + '/modify', (event, ...args) => {
    return modify(...args)
  })
  ipcMain.handle(MODEL_NAME + '/save', async (event, ...args) => {
    return await saveVideo(...args)
  })
  ipcMain.handle(MODEL_NAME + '/find', (event, ...args) => {
    return findVideo(...args)
  })
  ipcMain.handle(MODEL_NAME + '/count', (event, ...args) => {
    return countVideo(...args)
  })
  ipcMain.handle(MODEL_NAME + '/export', async (event, ...args) => {
    try {
      await exportVideo(...args);
      return { success: true };
    } catch (error) {
      console.error('Error exporting video:', error);
      throw error; // 将错误传回渲染进程
    }
  })

  ipcMain.handle(MODEL_NAME + '/remove', (event, ...args) => {
    return removeVideo(...args)
  })

  ipcMain.handle(MODEL_NAME + '/caption', (event, ...args) => {
    return captionVideo(...args)
  })

  ipcMain.handle(MODEL_NAME + '/printed', (event, ...args) => {
    return printedVideo(...args)
  })

  ipcMain.handle('file/getBuffer', async (event, filePath) => {
    try {
      return fs.readFileSync(filePath);
    } catch (err) {
      console.error('读取文件错误:', err);
      throw err;
    }
  });
}
